/*
SPDX-License-Identifier: Apache-2.0
*/

package main

import (
	"encoding/json"
	"fmt"

	"github.com/hyperledger/fabric-contract-api-go/contractapi"
)

// 智能合约
type SmartContract struct {
	contractapi.Contract
}

// 账本记录
type NcapRecord struct {
	Key        string `json:"key"`        // 唯一键 Key
	RecordJson string `json:"recordjson"` // 记录Json    RecordJson
}

type QueryResult struct {
	Key    string `json:"key"`
	Record *NcapRecord
}

// 初始化
func (s *SmartContract) InitLedger(ctx contractapi.TransactionContextInterface) error {
	arr := []NcapRecord{
		NcapRecord{
			Key:        "11",
			RecordJson: "{}",
		},
	}

	for _, one := range arr {
		oneAsBytes, _ := json.Marshal(one)
		err := ctx.GetStub().PutState(one.Key, oneAsBytes)

		if err != nil {
			return fmt.Errorf("存入世界状态失败。 %s", err.Error())
		}
	}

	return nil
}

func (s *SmartContract) GetCtxInfo(ctx contractapi.TransactionContextInterface, method string, param string) (string, error) {
	out := ""
	clientIdentity := ctx.GetClientIdentity()

	if method == "GetClientIdentity" {
		out = fmt.Sprintf("%+v", clientIdentity)
	} else if method == "GetMSPID" {
		mspid, err := clientIdentity.GetMSPID()
		if err != nil {
			return out, fmt.Errorf("%s", err.Error())
		}
		out = mspid
	} else if method == "GetX509Certificate" {
		cert, err := clientIdentity.GetX509Certificate()
		if err != nil {
			return out, fmt.Errorf("%s", err.Error())
		}
		out = fmt.Sprintf("%+v", cert)
	} else if method == "GetAttributeValue" {
		attrName := param
		v, b, err := clientIdentity.GetAttributeValue(attrName)
		if err != nil {
			return out, fmt.Errorf("%s", err.Error())
		}
		if !b {
			return out, fmt.Errorf("%s", "取值失败")
		}
		out = fmt.Sprintf("%s", v)
	} else if method == "" {
		return out, fmt.Errorf("未定义方法")
	}

	return out, nil
}

// 增加
func (s *SmartContract) InsertOne(ctx contractapi.TransactionContextInterface, key string, recordJson string) (string, error) {
	oneAsBytes, err := ctx.GetStub().GetState(key)
	if err != nil {
		return "", fmt.Errorf("从账本获取数据失败, %s", err.Error())
	}
	if oneAsBytes != nil {
		return "", fmt.Errorf("记录已存在,key=%s", key)
	}

	one := NcapRecord{
		Key:        key,
		RecordJson: recordJson,
	}

	oneAsBytes, err = json.Marshal(one)
	if err != nil {
		return "", fmt.Errorf("object转化成为json失败, %s", err)
	}

	err = ctx.GetStub().PutState(key, oneAsBytes)
	if err != nil {
		return "", fmt.Errorf("put失败，%s", err)
	}

	chaincodeStubInterface := ctx.GetStub()

	var txid string

	txid = chaincodeStubInterface.GetTxID()

	return txid, nil
}

// 删除
func (s *SmartContract) DeleteOne(ctx contractapi.TransactionContextInterface, key string) (*NcapRecord, error) {
	oneAsBytes, err := ctx.GetStub().GetState(key)

	if err != nil {
		return nil, fmt.Errorf("从账本获取数据失败, %s", err.Error())
	}

	if oneAsBytes == nil {
		return nil, fmt.Errorf("记录不存在,key=%s", key)
	}

	err = ctx.GetStub().DelState(key)
	if err != nil {
		return nil, fmt.Errorf("删除记录失败，%s", err)
	}

	one := new(NcapRecord)
	_ = json.Unmarshal(oneAsBytes, one)

	return one, nil
}

// 更新
func (s *SmartContract) UpdateOne(ctx contractapi.TransactionContextInterface, key string, recordJson string) error {

	oneAsBytes, err := ctx.GetStub().GetState(key)

	if err != nil {
		return fmt.Errorf("从账本获取数据失败, %s", err.Error())
	}

	if oneAsBytes == nil {
		return fmt.Errorf("记录不存在,key=%s", key)
	}

	// ------------------------- json -----------------------
	one := NcapRecord{
		Key:        key,
		RecordJson: recordJson,
	}
	oneAsBytes, err = json.Marshal(one)
	if err != nil {
		return fmt.Errorf("object转化成为json失败, %s", err)
	}

	err = ctx.GetStub().PutState(key, oneAsBytes)
	if err != nil {
		return fmt.Errorf("更新记录失败，%s", err)
	}

	return nil
}

// 查
func (s *SmartContract) QueryOne(ctx contractapi.TransactionContextInterface, key string) (*NcapRecord, error) {
	oneAsBytes, err := ctx.GetStub().GetState(key)

	if err != nil {
		return nil, fmt.Errorf("从账本获取数据失败, %s", err.Error())
	}

	if oneAsBytes == nil {
		return nil, fmt.Errorf("记录不存在,key=%s", key)
	}

	one := new(NcapRecord)
	_ = json.Unmarshal(oneAsBytes, one)

	return one, nil
}

// 记录总数
func (s *SmartContract) GetTotalCount(ctx contractapi.TransactionContextInterface) (int, error) {
	startKey := ""
	endKey := ""

	resultsIterator, err := ctx.GetStub().GetStateByRange(startKey, endKey)

	if err != nil {
		return -1, err
	}
	defer resultsIterator.Close()

	results := []QueryResult{}

	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()

		if err != nil {
			return -1, err
		}

		one := new(NcapRecord)
		_ = json.Unmarshal(queryResponse.Value, one)

		queryResult := QueryResult{Key: queryResponse.Key, Record: one}
		results = append(results, queryResult)
	}
	count := len(results)

	return count, nil
}

// 最新记录
func (s *SmartContract) GetLastestRecord(ctx contractapi.TransactionContextInterface) (*NcapRecord, error) {
	startKey := ""
	endKey := ""
	resultsIterator, err := ctx.GetStub().GetStateByRange(startKey, endKey)

	if err != nil {
		return nil, err
	}
	defer resultsIterator.Close()

	results := []QueryResult{}

	for resultsIterator.HasNext() {
		queryResponse, err := resultsIterator.Next()

		if err != nil {
			return nil, err
		}

		one := new(NcapRecord)
		_ = json.Unmarshal(queryResponse.Value, one)

		queryResult := QueryResult{Key: queryResponse.Key, Record: one}
		results = append(results, queryResult)
	}

	queryOne := results[len(results)-1]

	one := queryOne.Record

	return one, nil
}

func main() {

	// 新建链码
	chaincode, err := contractapi.NewChaincode(new(SmartContract))

	if err != nil {
		fmt.Printf("创建链码失败: %s", err.Error())
		return
	}

	// 链码启动
	if err := chaincode.Start(); err != nil {
		fmt.Printf("启动链码失败，%s", err.Error())
	}
}
